%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Observable port objects

% Author: Peter Van Roy
% Date: Nov. 26, 2008

% See section 5.2.1 of CTM (page 351).

% We extend the creation of port objects by adding an
% observer of the successive internal states of the
% port object.  We can use this observer, e.g., to
% debug a multi-agent system.  This is an example of
% separation of concerns: the port object's
% specification is not changed.

% C={NewPortObject Init Fun}: create a port object
% with initial state Init and transition function Fun

% C={NewPortObjectObserve Init Fun S}: create a port
% object with initial state Init, transition function
% Fun, and stream S of internal states.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Step 1:
% We start with the definition of NewPortObject using
% FoldL.  FoldL implements an accumulator.  This is an
% example of using a functional building block as a
% concurrency pattern.
declare
fun {NewPortObject Init Fun}
   Sin Out in    
   thread {FoldL Sin Fun Init Out} end
   {NewPort Sin}
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Step 2:
% We extend NewPortObject with an extra argument that
% returns a stream of the internal states of the port
% object.  The new function NewPortObjectObserve is
% also defined using FoldL, simply by giving it a
% new transition function that keeps track of both the
% current state and the end of the state stream.

% Note: another possible definition would be to define
% a second port and to send the internal states to this
% port.  This definition is too general since we do not
% need the nondeterminism of ports to keep track of
% the internal states.
declare
fun {NewPortObjectObserve Init Fun ?SHead}
   Sin Out STail in
   SHead=Init|STail
   thread {FoldL Sin
	   fun {$ STail#State Msg} State2 STail2 in
	      State2={Fun State Msg}
	      STail=State2|STail2
	      STail2#State2
	   end
	   STail#Init Out}
   end
   {NewPort Sin}
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Example execution
% Here is the state transition function for a port
% object that implements an up/down counter
declare
fun {CFun State Msg}
   case Msg of inc then State+1
   [] dec then State-1
   [] get(X) then X=State State end
end

% We define a counter object
% The first object is a straightforward counter
declare
C1={NewPortObject 0 CFun}

% Send messages to the first object
{Send C1 inc}
{Send C1 dec}
{Browse {Send C1 get($)}}

% We define a second counter with the same behavior
% whose internal states are returned as a stream
declare C2 S2 in
C2={NewPortObjectObserve 0 CFun S2}
% Observe the internal states
{Browse S2}

% Send messages to the second object
{Send C2 inc}
{Send C2 dec}
{Browse {Send C2 get($)}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
